package org.example.repository;

import io.avaje.inject.Component; // Use Avaje Inject's component annotation
import io.ebean.Database;
import io.ebean.PagedList;
import jakarta.inject.Inject; // Use standard Jakarta Inject

import org.apache.commons.lang3.StringUtils;
import org.example.domain.User;
import org.example.domain.query.QUser;
import org.example.param.UserQueryParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.util.List;
import java.util.Optional;

@Component // Marks this as a component managed by Avaje Inject (effectively a Singleton)
public class UserRepository {

    private static final Logger log = LoggerFactory.getLogger(UserRepository.class);

    private final Database db; // Ebean Database instance

    @Inject // Tell Avaje Inject to inject the Database bean created by DbConfig
    public UserRepository(Database db) {
        this.db = db;
    }

    public Optional<User> findById(Long id) {
        log.debug("Finding user by id: {}", id);
        User user = db.find(User.class, id);
        return Optional.ofNullable(user);
    }

    public List<User> findAll(String name) {
        log.debug("Finding all users");
        QUser query = new QUser();
        if (name != null && !name.isEmpty()) {
            log.debug("Filtering users by name: {}", name);
            query.name.icontains(name);
        }
        return query.findList();
    }

    public User save(User user) {
        log.debug("Saving user: {}", user.getName());
        db.save(user); // Ebean handles insert vs update based on ID presence
        return user; // User object now has the generated ID if it was an insert
    }

    public Optional<User> update(Long id, User updatedUserData) {
        log.debug("Updating user with id: {}", id);
        Optional<User> existingUserOpt = findById(id);
        if (existingUserOpt.isPresent()) {
            User existingUser = existingUserOpt.get();
            // Only update fields that are meant to be updated
            existingUser.setName(updatedUserData.getName());
            existingUser.setEmail(updatedUserData.getEmail());
            // Let Ebean handle @WhenModified and @Version
            db.update(existingUser); // Explicitly use update for clarity
            return Optional.of(existingUser);
        } else {
            log.warn("User not found for update, id: {}", id);
            return Optional.empty();
        }
    }

    public boolean deleteById(Long id) {
        log.debug("Deleting user by id: {}", id);
        // Option 1: Find then delete (allows checking existence)
        User user = db.find(User.class, id);
        if (user != null) {
            db.delete(user);
            return true;
        }
        return false;
        // Option 2: Direct delete (returns rows affected)
        // int rows = db.delete(User.class, id);
        // return rows > 0;
    }

    public PagedList<User> findPageList(UserQueryParam userQueryParam) {
        log.debug("Finding users with query param: {}", userQueryParam);
        QUser query = new QUser();

        if (StringUtils.isNotBlank(userQueryParam.getName())) {
            query.name.contains(userQueryParam.getName());
        }

        userQueryParam.applyPage(query);
        userQueryParam.applySort(query);

        return query.findPagedList();
    }
}